package data

import (
	"fmt"
	"log/slog"
	"rule/expression"
	"rule/model"
	"time"
)

func ruleWork(_ruleDef *model.RuleDef) {
	if _ruleDef == nil {
		slog.Error("见鬼了ruleWork,_ruleDef空")
		return
	}
	if _ruleDef.Status != "1" {
		slog.Error("见鬼了ruleWork,_ruleDef,Status不是1")
		return
	}
	// 上面是冗余校验
	// 下面是正式代码
	// 在英语中, 毫秒的缩写通常是“ms” ; “微秒”的缩写通常是“μs”或“us”;
	_nowms := time.Now().UnixMilli() // 毫秒 13位时间戳

	boolExpr := _ruleDef.BoolExpr
	ruleItems := deepCopyRuleItems(_ruleDef.RuleItems)

	slog.Warn("规则触发,rule_id="+_ruleDef.RuleId, "now_ms", _nowms)

	// 把每一个小规则 取数据
	// 为了快速读取所有数据, 才写了2个for循环 定义取数 开始时间
	startCollect := time.Now().UnixNano()
	ruleDatas := make([][]*TsValue, len(ruleItems))
	for i, _ruleItem := range ruleItems {
		ptid := _ruleItem.PtId
		_after_ms := _nowms - int64(_ruleItem.Duration*1000)

		ptIdQueue := QueueMap.GetQueue(ptid) // 内部有判断，不可能nil
		tsVals := ptIdQueue.RecentValues(_after_ms)
		ruleDatas[i] = tsVals
		fmt.Println("ptid,_after_ms=", ptid, "tsVals长度", len(tsVals))

		//if ptid == "1000520656" {
		//	slog.Debug("特别特别1000520656+tsVals" + spew.Sdump(tsVals))
		//}
	}
	endCollect := time.Now().UnixNano()
	//
	// fmt.Println("规则rule_id="+_ruleDef.RuleId+"数据采集时间,纳秒:", endCollect-startCollect)
	debugStr := fmt.Sprintf("规则rule_id=%s,数据采集时间,纳秒:%d", _ruleDef.RuleId, endCollect-startCollect)
	slog.Info(debugStr)

	params := make([]BooleanParam, len(ruleDatas)) // 日志专用
	parameters := make(map[string]any, len(ruleItems))
	for i, _ruleItem := range ruleItems {
		_abbr, _b := CalcRuleItemBoolean(_ruleItem, ruleDatas[i])
		parameters[_abbr] = _b
		params[i] = BooleanParam{_abbr, _b}
	}
	//
	currentBool := expression.CalcBoolean(boolExpr, parameters)

	slog.Info("特别注意大规则结果,规则rule_id="+_ruleDef.RuleId, "当前布尔", currentBool, "rule_expr", boolExpr, "params", params)
	//------------------业务逻辑判断
	if !currentBool {
		// 不能反控
		// 更新上次结果 为false
		if _ruleDef.LastBool {
			_ruleDef.LastBool = false
		}
		return
	}

	if _ruleDef.LastBool { // _ruleDef.LastBool && currentBool
		slog.Info("特别注意上次True当前True跳过,规则rule_id=" + _ruleDef.RuleId)
		return
	}

	_ruleDef.LastBool = true
	//------------------业务逻辑判断

	// 反控代码,反控相关
	reverseCtrl(_ruleDef.Id, _ruleDef.RuleId, _ruleDef.LinkageList)
}

func CalcRuleItemBoolean(_ruleItem model.RuleItem, _tsVals []*TsValue) (_boolAbbr string, _b bool) {
	_boolAbbr = _ruleItem.BoolAbbr
	if len(_tsVals) < 1 {
		slog.Warn("calc_bool_ret,err数据长度过短;"+_boolAbbr, "pt_id", _ruleItem.PtId)
		return _boolAbbr, false
	}
	if _ruleItem.Type == model.RuleTypeNormal {
		_b = calcRuleNormal(_ruleItem, _tsVals)
		return
	} else if _ruleItem.Type == model.RuleTypeCount {
		_b = calcRuleCount(_ruleItem, _tsVals)
		return
	} else if _ruleItem.Type == model.RuleTypeChange {
		_b = calcRuleChange(_ruleItem, _tsVals)
		return
	}
	return
	//
}

func calcRuleNormal(_ruleItem model.RuleItem, _tsVals []*TsValue) bool {
	for i := 0; i < len(_tsVals); i++ {
		_v := _tsVals[i].V
		_b, err := expression.CalcExpressionWithValue(_ruleItem.LeftExpr, _v)
		if err != nil {
			slog.Error("calc_err_calcRuleNormal", "error", err.Error())
			return false
		}
		if !_b {
			// 假
			// 一个假的 别的都不用判断了
			slog.Debug("calc_bool_ret_normal", "pt_id", _ruleItem.PtId, "_val", _tsVals[i])
			return false
		}
	}
	return true
}

func calcRuleCount(_ruleItem model.RuleItem, _tsVals []*TsValue) bool {
	var _trueCnt int = 0
	flagList := make([]bool, 0, len(_tsVals))
	for i := 0; i < len(_tsVals); i++ {
		_v := _tsVals[i].V
		_b, err := expression.CalcExpressionWithValue(_ruleItem.LeftExpr, _v)
		if err != nil {
			slog.Error("calc_err_calcRuleCount", "error", err.Error())
			return false
		}
		if _b {
			_trueCnt = _trueCnt + 1
			flagList = append(flagList, true)
		} else {
			flagList = append(flagList, false)
		}
	}

	// count 表达式
	slog.Info("calc_bool_ret_count", "pt_id", _ruleItem.PtId, "count次数", _trueCnt)
	//
	currentBool, err := expression.CalcExpressionWithValue(_ruleItem.CountExpr, _trueCnt)
	if err != nil {
		slog.Error("calc_err_calcRuleCount", "error", err.Error())
		return false
	}
	return currentBool
}

func calcRuleChange(_ruleItem model.RuleItem, _tsVals []*TsValue) bool {
	if len(_tsVals) < 2 {
		slog.Warn("calc_bool_ret,err数据长度过短", "pt_id", _ruleItem.PtId)
		return false
	}

	// flagList 是纯测试才有用的数据
	var _changeCnt int = 0
	var _compareCnt int = len(_tsVals) - 1
	flagList := make([]bool, 0, _compareCnt)
	// flagList 统计每一次的数据
	slog.Debug("特别特别" + fmt.Sprintf("比较次数:%d\n", _compareCnt))

	for i := 0; i < _compareCnt; i++ {
		_l := _tsVals[i].V
		_r := _tsVals[i+1].V
		// slog.Debug("特别特别" + fmt.Sprintf("_l == _ruleItem.Left && _r == _ruleItem.Right;%s == %s && %s == %s", _l, _ruleItem.Left, _r, _ruleItem.Right))
		if _l == _ruleItem.Left && _r == _ruleItem.Right {
			_changeCnt = _changeCnt + 1
			flagList = append(flagList, true)
		} else {
			flagList = append(flagList, false)
		}
	}
	// , "flagList", flagList
	slog.Info("calc_bool_ret_change", "pt_id", _ruleItem.PtId, "_compare次数", _compareCnt, "change次数", _changeCnt)

	currentBool, err := expression.CalcExpressionWithValue(_ruleItem.ChangeExpr, _changeCnt)
	if err != nil {
		slog.Error("calc_err_calcRuleChange", "error", err.Error())
		return false
	}
	return currentBool
}

func deepCopyRuleItems(src []model.RuleItem) []model.RuleItem {
	dst := make([]model.RuleItem, len(src))
	for i, p := range src {
		dst[i] = model.RuleItem{
			RuleBase:   p.RuleBase,
			LeftExpr:   p.LeftExpr,
			CountExpr:  p.CountExpr,
			Left:       p.Left,
			Right:      p.Right,
			ChangeExpr: p.ChangeExpr,
		}
	}
	return dst
}
